/*
  Name: Firework
  Description:
  Version: 1.0
  Author: Noritaka Horio
  Website: http://sharedhat.heteml.jp/
*/

Firework fwork;

void setup() {
  float x, y;
  size(300,165);
  background(#ffffff);
  smooth();
  frameRate(20);
  strokeWeight(1);

  fwork = new Firework(200, height);
}

void draw() {
  fwork.draw();
}

class Firework {
  float x, y;
  FireworkState state;

  Firework(float x, float y) {
    this.x = x;
    this.y = y;

    FireworkState fw = new GrowState(this);
    fw.setNextState(new SparkState(this));

    this.state = fw;
  }

  void draw() {
    this.state.draw();
  }

}

class GrowState extends FireworkState {

//  int strokeLength = 5;
  float stopY = 0;
  float startY, endY;

  GrowState(Firework fw) {
    super(fw);
    this.stopY = int(random(0, 200));
    this.startY = this.fw.y; 
    this.endY  = this.fw.y;
  }

  void update() {
    this.startY = this.endY;
    float diffY = this.startY - this.stopY; 
    this.endY = this.startY - diffY * 0.05;
  }
  
  void draw() {
    line(this.fw.x, this.startY, this.fw.x, this.endY);
    this.update();
  }

}

class SparkState extends FireworkState {

//  int strokeLength = 5;
// float stopY = 0;
//  float startY, endY;
  int count = 36;
  float[] endX, endY, startX, startY;
  float r = 100;

  SparkState(Firework fw) {
    super(fw);

    this.endX    =  new float[this.count];
    this.endY    =  new float[this.count];
    this.startX  =  new float[this.count];
    this.startY  =  new float[this.count];

    for (int i = 0; i < this.count; i++) {
      this.startX[i] = this.fw.x;
      this.startY[i] = this.fw.y;
    }
  }

  void update() {
    for (int i = 0; i < this.count; i++) {
      float x = cos(i * 10) * this.r + this.startX[i];
      float y = sin(i * 10) * this.r + this.startY[i];
      this.endX[i] = (this.startX[i] - x) * 0.05;
      this.endY[i] = (this.startY[i] - y) * 0.05;
    }
  }
  
  void draw() {
    for (int i = 0; i < this.count; i++) {
      line(this.startX[i], this.startY[i], this.endX[i], this.endY[i]);
    }
    this.update();
  }

}



class FireworkState {

  Firework fw;
  FireworkState st;

  FireworkState(Firework fw) {
    this.fw = fw;
  }

  boolean setNextState(FireworkState state) {
    this.st = state;
    return true; 
  }

  FireworkState nextState() {
    return this.st;
  }

  void draw() {
  }

}
